using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class EnemyStateManager : MonoBehaviour
{
    [Header("Editable in Editor")]
    public EnemyType thisType;
    public string specialObjectID;
    public LayerMask targetLayer = 1 << 3;
    public GameObject bulletPrefab;
    public bool withGun;
    public float attackRange;
    public float attackCD;
    public float bulletSpeed;
    public float fireCD;
    public float rushSpeed;
    public float normalSpeed;
    public float patrolRadius = 5f;
    public float patrolWaitTime = 2f;
    public float rotationSpeed;
    public float viewDistance = 2.5f;
    public float viewAngle = 20f;
    public float lostTime = 10f;
    public float sniffTime;

    [HideInInspector] public EnemyState currentState;
    private bool isBattle = false;
    private bool isActing = true;
    [HideInInspector] public bool isMoving = false;
    private bool findPlayer = false;
    private bool haveTarget = false;
    private bool isAttack = false;
    private float lastLostTime;
    public float lastAttackCD;
    private float lastFireCD;
    private NavMeshAgent navAgent;
    private Rigidbody2D rb;
    private Vector2 initialPosition;
    [HideInInspector] public Vector2 targetPosition;
    private Vector2 patrolCenter;
    private Vector2 currentDirection;
    private Transform playerTransform;
    private Coroutine I_moveWithTurnFirst;
    private Coroutine I_turnToDirection;
    private Coroutine I_waitThenTurnAndMove;
    private List<Vector3> pathPointList = new List<Vector3>();
    private int currentIndex = 0;
    private float currentSpeed;
    private Vector3[] currentPath;

    [Header("Movement Debug")]
    public bool showMoveGizmo = true;
    public bool showVisionArea = true;
    public bool showDirection = true;
    public bool showPathDebug = true;

    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        navAgent = GetComponent<NavMeshAgent>();

        // Configure NavMeshAgent: use only for path calculation
        if (navAgent != null)
        {
            navAgent.updateRotation = false;
            navAgent.updatePosition = false;
            navAgent.enabled = false; // Disable automatic movement
        }
        else
        {
            Debug.LogError("NavMeshAgent component is missing on " + gameObject.name);
        }

        transform.eulerAngles = Vector3.zero;
        targetPosition = transform.position;
        initialPosition = transform.position;
        playerTransform = GameObject.FindGameObjectWithTag("Player")?.transform;
        currentDirection = transform.up;
        currentSpeed = normalSpeed;

        if (rb != null)
        {
            rb.gravityScale = 0;
        }
    }

    private void Update()
    {
        CheckForPlayerInSight();
        StateUpdate();
    }

    private void OnDisable()
    {
        // Handle death animation or cleanup if needed
    }

    private void StateUpdate()
    {
        switch (currentState)
        {
            case EnemyState.Normal:
                if (thisType == EnemyType.Patrol)
                {
                    if (targetPosition == Vector2.zero)
                    {
                        targetPosition = initialPosition;
                    }
                }
                break;

            case EnemyState.PatrolAroundBody:
                if (!haveTarget)
                {
                    // Patrol logic handled by PatrolAround()
                }
                break;

            case EnemyState.FindPlayer:
                if (!isBattle)
                {
                    BattleStart();
                }
                if (isActing && isBattle)
                {
                    LookAtPlayer();
                    if (withGun)
                    {
                        lastFireCD -= Time.deltaTime;
                        if (lastFireCD <= 0)
                        {
                            EnemyFire();
                            lastFireCD = fireCD;
                        }
                    }
                    else
                    {
                        if (playerTransform != null)
                        {
                            MoveTo(playerTransform.position, rushSpeed);
                            float distanceToPlayer = Vector2.Distance(transform.position, playerTransform.position);
                            if (lastAttackCD <= 0 && distanceToPlayer <= attackRange)
                            {
                                StartCoroutine(PerformMeleeAttack(playerTransform.GetComponent<Collider2D>()));
                            }
                            else if (lastAttackCD > 0)
                            {
                                lastAttackCD -= Time.deltaTime;
                            }
                        }
                    }
                }
                break;
        }
    }

    public void CheakSound(Vector2 soundPosition)
    {
        if (currentState == EnemyState.Normal)
        {
            currentState = EnemyState.FirstSound;
        }
        else if (currentState == EnemyState.FirstSound)
        {
            currentState = EnemyState.SecondSound;
            targetPosition = soundPosition;
            currentSpeed = rushSpeed;
            MoveTo(targetPosition, rushSpeed);
        }
    }

    public void GetInfo(Vector2 bodyPosition)
    {
        currentState = EnemyState.FindBody;
        targetPosition = bodyPosition;
        currentSpeed = rushSpeed;
        MoveTo(targetPosition, rushSpeed);
    }

    #region Combat

    private IEnumerator PerformMeleeAttack(Collider2D playerCollider)
    {
        if (isAttack) yield break;
        isAttack = true;

        Health playerHealth = playerCollider.GetComponent<Health>();
        if (playerHealth != null)
        {
            playerHealth.HP -= 1;
            Debug.Log("Enemy attacks player! HP: " + playerHealth.HP);
            if (playerHealth.HP <= 0)
            {
                playerHealth.Dead();
            }
        }

        lastAttackCD = attackCD;
        yield return new WaitForSeconds(0.1f);
        isAttack = false;
    }

    private void BattleStart()
    {
        if (I_moveWithTurnFirst != null)
        {
            StopCoroutine(I_moveWithTurnFirst);
        }
        if (I_turnToDirection != null)
        {
            StopCoroutine(I_turnToDirection);
        }
        if (I_waitThenTurnAndMove != null)
        {
            StopCoroutine(I_waitThenTurnAndMove);
        }

        lastFireCD = fireCD;
        isBattle = true;
    }

    private void LookAtPlayer()
    {
        if (playerTransform == null) return;
        Vector2 direction = ((Vector2)playerTransform.position - (Vector2)transform.position).normalized;
        RotateTowardsDirection(direction);
    }

    private void EnemyFire()
    {
        if (playerTransform == null) return;

        Vector2 direction = ((Vector2)playerTransform.position - (Vector2)transform.position).normalized;
        GameObject bullet = Instantiate(bulletPrefab, transform.position, Quaternion.identity);

        float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        bullet.transform.rotation = Quaternion.Euler(0, 0, angle);

        Rigidbody2D bulletRb = bullet.GetComponent<Rigidbody2D>();
        if (bulletRb != null)
        {
            bulletRb.velocity = direction * bulletSpeed;
        }
    }

    #endregion

    #region Movement

    private void RotateTowardsDirection(Vector2 direction)
    {
        if (direction.sqrMagnitude < 0.01f) return;

        float targetAngle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        float currentAngle = transform.eulerAngles.z;
        float smoothedAngle = Mathf.MoveTowardsAngle(currentAngle, targetAngle, rotationSpeed * Time.deltaTime);
        transform.rotation = Quaternion.Euler(0, 0, smoothedAngle);

        currentDirection = direction;
    }

    public void MoveTo(Vector2 position, float speed)
    {
        targetPosition = position;
        currentSpeed = speed;
        if (I_moveWithTurnFirst != null)
        {
            StopCoroutine(I_moveWithTurnFirst);
        }
        I_moveWithTurnFirst = StartCoroutine(MoveAlongPath());
    }

    public void PatrolAround(Vector2 centerPosition)
    {
        patrolCenter = centerPosition;
        GetNewRandomTarget();
        currentSpeed = normalSpeed;
        if (I_moveWithTurnFirst != null)
        {
            StopCoroutine(I_moveWithTurnFirst);
        }
        I_moveWithTurnFirst = StartCoroutine(MoveAlongPath());
    }

    public void Return()
    {
        MoveTo(initialPosition, normalSpeed);
    }

    private void GetNewRandomTarget()
    {
        Vector2 center = patrolCenter != Vector2.zero ? patrolCenter : transform.position;
        Vector2 randomOffset = Random.insideUnitCircle * patrolRadius;
        Vector2 randomPos = center + randomOffset;

        if (NavMesh.SamplePosition((Vector3)randomPos, out NavMeshHit hit, 2f, navAgent.areaMask))
        {
            targetPosition = hit.position;
        }
        else
        {
            targetPosition = randomPos;
        }
    }

    private IEnumerator MoveAlongPath()
    {
        NavMeshPath path = new NavMeshPath();
        bool success = NavMesh.CalculatePath(transform.position, targetPosition, NavMesh.AllAreas, path);

        if (!success || path.status != NavMeshPathStatus.PathComplete)
        {
            Debug.LogWarning("Path calculation failed or incomplete");
            yield break;
        }

        pathPointList = new List<Vector3>(path.corners);
        currentPath = path.corners;
        currentIndex = 0;

        if (pathPointList.Count == 0)
        {
            yield break;
        }

        isMoving = true;

        while (currentIndex < pathPointList.Count)
        {
            Vector3 currentTarget = pathPointList[currentIndex];
            Vector2 direction = ((Vector2)currentTarget - (Vector2)transform.position).normalized;

            if (Vector2.Distance(transform.position, currentTarget) < 0.1f)
            {
                transform.position = currentTarget;
                currentIndex++;
                continue;
            }

            yield return StartCoroutine(TurnToDirection(direction));

            while (Vector2.Distance(transform.position, currentTarget) > 0.1f)
            {
                Vector2 moveDelta = direction * currentSpeed * Time.deltaTime;
                rb.MovePosition(rb.position + moveDelta);

                // Check if another coroutine has replaced this one (movement interrupted)
                if (I_moveWithTurnFirst != this.StartCoroutine(MoveAlongPath()))
                {
                    isMoving = false;
                    yield break;
                }

                yield return null;
            }

            transform.position = currentTarget;
            currentIndex++;
        }

        isMoving = false;
    }

    private IEnumerator TurnToDirection(Vector2 direction)
    {
        if (direction.sqrMagnitude < 0.01f) yield break;

        float targetAngle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        float currentAngle = transform.eulerAngles.z;

        while (true)
        {
            float angleDiff = Mathf.DeltaAngle(currentAngle, targetAngle);
            if (Mathf.Abs(angleDiff) <= 1f)
            {
                transform.eulerAngles = new Vector3(0, 0, targetAngle);
                break;
            }

            float turnStep = rotationSpeed * Time.deltaTime;
            float newAngle = Mathf.MoveTowardsAngle(currentAngle, targetAngle, turnStep);
            transform.eulerAngles = new Vector3(0, 0, newAngle);

            currentAngle = newAngle;
            yield return null;
        }
    }

    #endregion

    #region Vision

    private void CheckForPlayerInSight()
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, viewDistance, targetLayer);

        foreach (Collider2D col in colliders)
        {
            if (col.CompareTag("Player"))
            {
                Vector2 dirToTarget = ((Vector2)col.transform.position - (Vector2)transform.position).normalized;
                float angle = Vector2.Angle(transform.up, dirToTarget);

                if (angle <= viewAngle)
                {
                    float distance = Vector2.Distance(transform.position, col.transform.position);
                    if (distance <= viewDistance)
                    {
                        RaycastHit2D hit = Physics2D.Raycast(transform.position, dirToTarget, distance, LayerMask.GetMask("Obstacle", "Wall"));
                        if (!hit.collider)
                        {
                            if (currentState != EnemyState.FindPlayer)
                            {
                                currentState = EnemyState.FindPlayer;
                            }
                            lastLostTime = lostTime;
                            targetPosition = col.transform.position;
                            findPlayer = true;
                        }
                    }
                }
            }
            else if (col.CompareTag("Body"))
            {
                Vector2 dirToTarget = ((Vector2)col.transform.position - (Vector2)transform.position).normalized;
                float angle = Vector2.Angle(transform.up, dirToTarget);

                if (angle <= viewAngle)
                {
                    float distance = Vector2.Distance(transform.position, col.transform.position);
                    if (distance <= viewDistance)
                    {
                        if (patrolCenter != (Vector2)col.transform.position && currentState != EnemyState.FindPlayer)
                        {
                            patrolCenter = col.transform.position;
                            targetPosition = patrolCenter;
                            currentSpeed = rushSpeed;
                            AskOther(patrolCenter, 300f);
                        }
                    }
                }
            }
        }

        if (findPlayer && currentState == EnemyState.FindPlayer)
        {
            lastLostTime -= Time.deltaTime;
            if (lastLostTime <= 0)
            {
                findPlayer = false;
            }
        }
    }

    #endregion

    #region CallForHelp

    public void AskOther(Vector2 center, float radius, float duration = 0f)
    {
        GameObject tempObject = new GameObject("FindBody");
        tempObject.transform.position = center;

        CircleCollider2D circleCollider = tempObject.AddComponent<CircleCollider2D>();
        circleCollider.radius = radius;
        circleCollider.isTrigger = true;
        circleCollider.offset = Vector2.zero;

        tempObject.layer = LayerMask.NameToLayer("FindBody");

        Collider2D[] colliders = Physics2D.OverlapCircleAll(center, radius);
        foreach (Collider2D collider in colliders)
        {
            if (collider.CompareTag("Enemy"))
            {
                EnemyStateManager enemy = collider.GetComponent<EnemyStateManager>();
                if (enemy != null)
                {
                    enemy.GetInfo(center);
                }
            }
        }

        tempObject.AddComponent<MonoBehaviour>();
        Destroy(tempObject, duration);
    }

    #endregion

    #region Gizmos

    private void OnDrawGizmos()
    {
        if (showMoveGizmo)
        {
            Gizmos.color = Color.green;
            Gizmos.DrawSphere(targetPosition, 0.2f);

            if (showPathDebug && pathPointList != null && pathPointList.Count > 0)
            {
                Gizmos.color = Color.blue;
                for (int i = 0; i < pathPointList.Count - 1; i++)
                {
                    Gizmos.DrawLine(pathPointList[i], pathPointList[i + 1]);
                    Gizmos.DrawSphere(pathPointList[i], 0.1f);
                }
                Gizmos.DrawSphere(pathPointList[pathPointList.Count - 1], 0.1f);

                if (currentIndex < pathPointList.Count)
                {
                    Gizmos.color = Color.red;
                    Gizmos.DrawSphere(pathPointList[currentIndex], 0.15f);
                    Gizmos.DrawLine(transform.position, pathPointList[currentIndex]);
                }
            }
        }

        if (showVisionArea)
        {
            Gizmos.color = new Color(1, 1, 0, 0.1f);
            Gizmos.DrawSphere(transform.position, viewDistance);

            Vector3 rightBound = Quaternion.Euler(0, 0, viewAngle) * transform.up * viewDistance;
            Vector3 leftBound = Quaternion.Euler(0, 0, -viewAngle) * transform.up * viewDistance;

            Gizmos.color = Color.red;
            Gizmos.DrawRay(transform.position, rightBound);
            Gizmos.DrawRay(transform.position, leftBound);

            DrawArc(transform.position, viewDistance, -viewAngle, viewAngle, Color.red);
        }

        if (showDirection)
        {
            Gizmos.color = Color.white;
            Gizmos.DrawRay(transform.position, transform.up * 1.5f);

            if (rb != null && rb.velocity.magnitude > 0.1f)
            {
                Gizmos.color = Color.cyan;
                Gizmos.DrawRay(transform.position, rb.velocity.normalized * 1f);
            }
        }
    }

    private void DrawArc(Vector3 center, float radius, float fromAngle, float toAngle, Color color)
    {
        int segments = 20;
        float angleStep = (toAngle - fromAngle) / segments;

        Vector3 startDir = Quaternion.Euler(0, 0, fromAngle) * Vector3.up;
        Vector3 prevPoint = center + startDir * radius;

        for (int i = 1; i <= segments; i++)
        {
            float angle = fromAngle + i * angleStep;
            Vector3 dir = Quaternion.Euler(0, 0, angle) * Vector3.up;
            Vector3 nextPoint = center + dir * radius;
            Debug.DrawLine(prevPoint, nextPoint, color);
            prevPoint = nextPoint;
        }

        Debug.DrawLine(center, center + startDir * radius, color);
        Debug.DrawLine(center, center + Quaternion.Euler(0, 0, toAngle) * Vector3.up * radius, color);
    }

    #endregion
}
